<template>
  <view class="order-view">
    <ProgramModal
      :show="programModalVisible"
      :control="control"
      :selected-program-disabled="selectedProgramDisabled"
      :custom-adjust-option-title="customAdjustOptionTitle"
      @close="onProgramModalClose"
      @back="onProgramModalBack"
      @to-adjust="openAdjustParameter"
      @to-select-time="openTimeModal(SelectTimeEntry.SelectProgram)"
    />

    <AdjustParameterModal
      ref="adjustParameterRef"
      prevent-back
      custom-footer
      manual-load-parameter
      :show="adjustParameterVisible"
      :back-text="$t('Appliance.OrderProgram.SelectProgram.Title.Text')"
      :control="control"
      :picker-keys="pickerKeys"
      :custom-params="customParams"
      @back="onAdjustParameterBack"
    >
      <template #footer>
        <view class="footer-group">
          <TextButton size="large" :text="$t('APP.Common.Previous.Text')" @click="onAdjustParameterBack" />
          <TextButton
            size="large"
            :text="$t('Appliance.OrderProgram.SelectTime.Button.Text')"
            :disabled="isOffline === true"
            :plain-disabled="orderTimeDisabled"
            @click="openTimeModal(SelectTimeEntry.AdjustParameter)"
          />
        </view>
      </template>
    </AdjustParameterModal>

    <SelectTimeModal
      :show="timeModalVisible"
      :back-text="selectTimeBackTexts[currentSelectTimeEntry] || ''"
      :control="control"
      :actived-parameter-names="activedParameterNames"
      :actived-parameter-option="activedParameterOption"
      :using-valley-time="usingValleyTime"
      @back="onTimeModalBack"
      @confirm="orderProgramNow"
    />
  </view>
</template>

<script setup lang="ts">
import type { BaseController } from '@/controller/BaseAppliance/definition'
import ProgramModal from './programModal.vue'
import type { ApplianceProgram, ProgramSelectOption } from '@/api/appliance'
import type { CustomOption } from '../../components/parameterCard.vue'
import { useControlState } from '@/controller/BaseAppliance/useControl'
import AdjustParameterModal from '../adjustParameterModal.vue'
import TextButton from '@/common/textButton.vue'
import SelectTimeModal from './selectTimeModal.vue'
import {
  checkOrderProgramAccessable,
  checkOrderTimeAccessable,
  checkAdjustAccessable,
} from '@/controller/common/ErrorHandler/validator'
import { useI18n } from 'vue-i18n'
import { showLoading, useUniEvent, onceObserve, nextTickPromise } from '@/utils/mpHelper'
import { ValleyTimeOrder } from '@/constants/UniEventKeys'
import { RemoteChangeOrderObserve } from '@/controller/common/Program/program'

const props = defineProps<{
  show: boolean
  control: BaseController.Control
  /**
   * 调节参数Key 配置
   */
  pickerKeys?: string[] // 需要展示为Picker组件的 Key
  customParams?: CustomOption[] // 自定义处理逻辑的 Key (在Checkbox类型的卡片中显示)
  customAdjustOptionTitle?: string
  customSelectTimeBackTexts?: string
  selectedProgramDisabled?: boolean
}>()
const emit = defineEmits<{
  (e: 'update:show', show: boolean): void
  (e: 'close'): void
}>()

const i18n = useI18n()
const { isOffline, showControlView, orderTimeDisabled } = useControlState(props.control)
watch(
  () => props.show,
  (show) => {
    programModalVisible.value = show // 预约显示时 只打开选择程序
    adjustParameterVisible.value = false
    timeModalVisible.value = false
    // 是否可预约 根据available中是否存在 START/FINISH_IN_RELATIVE 判断
    // 所以需要在预约弹框打开时就调用available
    if (show) {
      props.control.store.loadAvailableParameter()
      // 监听Remote修改时 刷新available 用于规避Remote关闭时 不返回RelativeOptions的问题
      props.control.remote.addBatchObserve(RemoteChangeOrderObserve)
    } else {
      props.control.remote.removeBatchObserve(RemoteChangeOrderObserve)
    }
  }
)
function closeModal() {
  emit('update:show', false)
  emit('close')
  programModalVisible.value = false
  adjustParameterVisible.value = false
  timeModalVisible.value = false
  usingValleyTime.value = false
}
watch(
  () => showControlView.value,
  (showControlView) => {
    if (!showControlView && props.show) closeModal()
  }
)

/**
 * 选择程序
 */
const programModalVisible = ref(false)
function onProgramModalBack() {
  closeModal()
}
function onProgramModalClose() {
  closeModal()
}

/**
 * 调节参数
 */
const adjustParameterRef = ref<InstanceType<typeof AdjustParameterModal> | null>(null)
const adjustParameterVisible = ref(false)
const activedParameterNames = ref<string[]>([])
const activedParameterOption = ref<ProgramSelectOption[]>([])
function openAdjustParameter() {
  if (!checkAdjustAccessable(props.control)) return

  adjustParameterVisible.value = true
}
function onAdjustParameterBack() {
  adjustParameterVisible.value = false
}
function syncActivedParameterNames() {
  activedParameterNames.value = adjustParameterRef.value?.getActivedParameterNames() || []
}
function syncActivedParameterOption() {
  activedParameterOption.value = adjustParameterRef.value?.getParameterOptions() || []
}

/**
 * 选择时间
 */
enum SelectTimeEntry {
  SelectProgram,
  AdjustParameter,
}
const selectTimeBackTexts = computed<Record<SelectTimeEntry, string>>(() => ({
  [SelectTimeEntry.SelectProgram]: i18n.t('Appliance.OrderProgram.SelectProgram.Title.Text'),
  [SelectTimeEntry.AdjustParameter]:
    props.customSelectTimeBackTexts || i18n.t('Appliance.OrderProgram.AdjustOption.Title.Text'),
}))
const currentSelectTimeEntry = ref(SelectTimeEntry.SelectProgram)

const timeModalVisible = ref(false)
async function openTimeModal(entry: SelectTimeEntry) {
  // 切换程序后 检查是否完成relative加载 否则显示Loading等待加载完成再继续
  if (programRelativeLoading.value) {
    await showLoading(async () => {
      await onceObserve(() => programRelativeLoading.value)
      await nextTickPromise()
    }, i18n.t('Appliance.OrderProgram.Loading.Text'))
  }

  // 前置检查
  if (!checkOrderTimeAccessable(props.control)) return

  currentSelectTimeEntry.value = entry
  syncActivedParameterNames()
  syncActivedParameterOption()
  timeModalVisible.value = true
}
function onTimeModalBack() {
  timeModalVisible.value = false
  usingValleyTime.value = false
}

// 是否将Finish in relative 转换显示为预计xx:xx开始
const shouldTransformRelative = computed(() => props.control.store.transformRelativeOrderForced)
// 是否正在加载Remaining等数据
const programRelativeLoading = computed(() => props.control.store.programRelativeLoading)

/**
 * 立即预约
 */
const activeProgram = computed<ApplianceProgram.Scope | null>(() => props.control.store.currentProgram)
async function orderProgramNow(orderOptions: ProgramSelectOption[], trackData: any) {
  // 调接口前检查
  if (!checkOrderProgramAccessable(props.control)) return

  await props.control.store.orderProgramNow(activeProgram.value as ApplianceProgram.Scope, orderOptions, trackData)

  closeModal()
}

/**
 * 谷电时间检查跳转处理
 */
const usingValleyTime = ref(false)
useUniEvent(ValleyTimeOrder, async () => {
  timeModalVisible.value = true
  usingValleyTime.value = true
})
</script>

<style scoped lang="less">
.footer-group {
  display: flex;
  justify-content: space-around;
  align-items: center;
}
</style>
